HTML 5 Game Development - Tutorial step 2


Ok, pretty lame, I know

Let's point to step2 game

import 'dart_02/game.dart';

void main() {
  //launch the game
  HTML5Game game = new HTML5Game();
  game.startGame();
}

First, let's add a FPS counter. This will tell us how "smoothly" our game is rendering. This bit is taken from the Dart clock example, so I'll add nothing more

The current game is an infinite loop; the Player is "invincible". Let's print a health bar to display this information

  /**
   * Draw character information.
   */
  void draw(CanvasRenderingContext2D context) {
    //health
    int startPosX = 10;
    int startPosY = 10;
    int heigth = 20;
    int maxLength = 110;
    
    //calculate remaining health %
    int y = (health/100*(maxLength-startPosX)).round() ;
    //green - good
    context..fillStyle="green"
           ..fillRect(startPosX, startPosY, y , heigth);
    //red - bad
    context..fillStyle="red"
        ..fillRect(startPosX+y, startPosY, maxLength-y , heigth);
    super.draw(context);
  }

Then, let's catch the user input from the keyboard (sorry mobile user, it's just a small game). A classic WASD should do just fine; the user wants to escape, while the Monster will follow the Player around trying to kill him.

The Keyboard class is taken from here; I just want to point out something. It's another great use of the Future functionality (really use autocomplete and see what you can achieve with a couple of lines of code...it's just amazing)

  //
  lastComands = new List();
  //
  update() {
    //process keyboard event
    processKeyboardInput();
	//etc
  }
  
  processKeyboardInput() {
    if (keyBoard.isPressed(KeyCode.W))
      lastComands.add(Command.NORTH);
    if (keyBoard.isPressed(KeyCode.A))
      lastComands.add(Command.WEST);
    if (keyBoard.isPressed(KeyCode.D))
      lastComands.add(Command.EAST);
    if (keyBoard.isPressed(KeyCode.S))
      lastComands.add(Command.SOUTH);
  }

Ok, so now each turn we collect the user input and create a list of Command to execute that will modify the world.

The Command class is just an enumaration of the possible four directions a user can select.

Google, really? Still no "real" enum in the language??

In a more advanced game obviously the possible action performed by the user would be much powerful

/**
 * Command to be executed.
 */
class Command {
  final _direction;
  const Command._internal(this._direction);
  toString() => 'Enum.$_direction';

  static const NORTH = const Command._internal('NORTH');
  static const SOUTH = const Command._internal('SOUTH');
  static const WEST = const Command._internal('WEST');
  static const EAST = const Command._internal('EAST');
}

Now that we have collected the actions we want to "apply" the user input to the Player. Let's construct a mixin (see this for more detail ); in two words, a mixin is an interface with a default implementation that might be shared in multiple class hierarchies

/**
 * Mixin for the characters to execute a Command.
 */
abstract class Commander {
  void applyCommands(List l);
}


So our mixin Commander will be applied to our Player so that he can still extends Character and benefit from the Commander implementation (empty in this case).

  @override
  void applyCommands(List l) {
    for(Command c in l) {
      if(c != null) {
        switch (c) {
          case Command.NORTH:
            y = y-3;
            break;
          case Command.SOUTH:
            y = y+3;
            break;
          case Command.EAST:
            x = x+3;
            break;
          case Command.WEST:
            x = x-3;
            break;
        } 
      }
    }
  }

Ok, so now our Player will move around according to the user input. Summarizing in the update method, we have collected the user input and created a list of Command to apply to the Player. At the end of the method, we just need to clear the list for the next loop.

  update() {
    //process keyboard event
    processKeyboardInput();
    //hurt a little the hero
    p.decrementHealth();
    
    //move randmly the monster
    m.x = r.nextInt(WIDTH);
    m.y = r.nextInt(HEIGHT);
    
    //player move to escape
    p.applyCommands(lastComands);
    
    //clean player command list for the next loop
    lastComands.clear();
  }

Ok, let's try it out.

It doesn't look "real" with the monster moving around like crazy, let's fix that in step3



Theme Sponsored by: Roller Blinds, Cyprus Holidays, Walk in Baths